package com.bdqn;

import com.bdqn.pojo.Student;

/**
 * Hello world!
 */
public class App {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 第一种：通过对象.getClass()获取Class
        Student student = new Student();
        student.setName("张三丰");
        student.setSex("男");
        student.setAge(101);
        student.setClazz("T001");
        Class clazz1 = student.getClass();

        // 第二种：通过类.class获取Class
        Class clazz2 = Student.class;

        // 第三种：Class.forName()通过类的全路径获取Class
        Class clazz3 = Class.forName("com.bdqn.pojo.Student");

        Student newInstance = (Student) clazz3.newInstance();
        newInstance.setName("人工智能机器人");
        System.out.println("(Student) clazz3.newInstance().getName() --> " + newInstance.getName());

        System.out.println("--------------- 获取类型的基本信息 ---------------");
        // 以字符串形式返回该类型的名称
        System.out.println("clazz1.getName() --> " + clazz1.getName());

        // 以字符串形式返回该类型的简称
        System.out.println("clazz1.getSimpleName() --> " + clazz1.getSimpleName());

        // 获取该类型所在的包
        System.out.println("clazz1.getPackage() --> " + clazz1.getPackage());

        // 返回该类型的超类的Class实例
        System.out.println("clazz1.getSuperclass() --> " + clazz1.getSuperclass());

        // 返回该类型所实现的全部接口的Class实例
        Class[] interfaces = clazz1.getInterfaces();
        for (Class interfacesClass : interfaces) {
            System.out.println("interfacesClass: --> " + interfacesClass.getName());
        }

        // 返回该类型中包含的全部内部类的Class实例
        Class[] declaredClasses = clazz1.getDeclaredClasses();
        for (Class declaredClass : declaredClasses) {
            System.out.println("declaredClass: --> " + declaredClass.getName());
        }

        // 返回该类型所在的外部类的Class实例

        Student stu = new Student();
        String declaringClassResult = stu.showResult();
        System.out.println("declaringClassResult --> 1 " + declaringClassResult);
        String declaringClassHobby = stu.showHobby();
        System.out.println("declaringClassHobby --> 2 " + declaringClassHobby);

        // 返回该类型的所有修饰符
        int modifier = clazz1.getModifiers();
        System.out.println(modifier);
        // 是否是公开类
        // 4 --> 00000000 00000000 00000000 00000110
        // &
        // 1 --> 00000000 00000000 00000000 00000001
        // =
        // 5 --> 00000000 00000000 00000000 00000000
        // System.out.println(2 | 3);

        if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) {
            System.out.println("这个类访问修饰符是 public 的");
        } else {
            System.out.println("这个类访问修饰符是 default(package) 的");
        }

        if ((modifier & Modifier.FINAL) == Modifier.FINAL) {
            System.out.println("这个类是 final 的");
        }
        if ((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT) {
            System.out.println("这个类是 abstract 的");
        }
        if ((modifier & Modifier.INTERFACE) == Modifier.INTERFACE) {
            System.out.println("这个类是一个接口");
        }

        System.out.println("--------------- 获取构造方法信息 ---------------");

        Constructor constructorOne = clazz1.getConstructor(String.class, int.class);

        Constructor[] constructors = clazz1.getConstructors();

        for (Constructor constructor : constructors) {
            int cm = constructor.getModifiers();
            System.out.println(cm);

            if ((cm & Modifier.PUBLIC) == Modifier.PUBLIC) {
                System.out.println("访问修饰符是 public 的");
            } else if ((cm & Modifier.PROTECTED) == Modifier.PROTECTED) {
                System.out.println("访问修饰符是 protected 的");
            } else if ((cm & Modifier.PRIVATE) == Modifier.PRIVATE) {
                System.out.println("访问修饰符是 private 的");
            } else {
                System.out.println("访问修饰符是 default(package) 的");
            }

            // 获得构造方法的参数类型列表
            Class[] parameterTypes = constructor.getParameterTypes();
            if (parameterTypes.length == 0) {
                System.out.println("该构造方法没有参数");
            } else {
                System.out.print("该构造方法的参数列表为：[");
                int i = 0;
                for (Class parameterType : parameterTypes) {
                    if (i != 0) {
                        System.out.print(", ");
                    }
                    System.out.print(parameterType.getName());
                    i++;
                }
                System.out.print("]\n");
            }
        }

        // getField()只能获取public的属性
        // Field nameField = clazz1.getField("clazz");
        // System.out.println("nameField.getType() --> " + nameField.getType());
        // getDeclaredField()可以获取到所有访问修饰符的属性
        Field nameField = clazz1.getDeclaredField("clazz");
        System.out.println("nameField.getType() --> " + nameField.getType());

        // 设置属性访问权限（true：越过访问权限限制）
        nameField.setAccessible(true);

        // 参数：从哪个对象中取出值
        String value = (String) nameField.get(student);
        System.out.println("nameField.get(student) --> " + value);

        // 操作name属性：给student这个对象的name属性设置值为"T312"
        nameField.set(student, "T312");

        // 参数：从哪个对象中取出值
        value = (String) nameField.get(student);
        System.out.println("nameField.get(student) --> " + value);

        System.out.println("操作方法");
        Method[] methods = clazz1.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }

        Method getClazz = clazz1.getDeclaredMethod("getClazz", null);

        // 设置方法访问权限（true：越过访问权限限制）
        getClazz.setAccessible(true);

        // 操作getClazz方法：给student这个对象的name属性设置值为"T312"
        String result = (String) getClazz.invoke(student, null);
        System.out.println("getClazz.invoke(student, null) --> " + result);
    }
}
